#include<iostream>
using namespace std;
//decltype可以在编译阶段推导出一个表达式类型
//decltype(表达式)
//基于表达式推导出一个新的类型
class Test
{
    public:
        int a = 10;
};
//2.表达式是函数调用，推导出的类型与函数返回值类型一致 如果不是类类型携带的const volatile限定符 会被省略
int func_int(){};
int &func_int_r(){};
int &&func_int_rr(){};
const int func_cint(){};
const int &func_cint_r(){};
const int &&func_cint_rr(){};
// const Test func_ctest(){};类中的函数调用推导会保留限定const等
void func()
{
    int a = 10;
    decltype(a) b; //推导出 b->int ;
    decltype(a + 3.14) c; //推导出c ->double;
    decltype(a+b*c) d ; //b->double；
    //decltype可以推导出复杂的表达式，而且可以不用初始化其变量 auto只能推导出已经初始化的变量类型
    //1.表达式为普通变量或者普通表达式或者类表达式 
    //这种情况下 推导出来的类型和表达式类型一致
    b = 10;
}
//表达式是一个左值（可以取地址的变量），或者被括号（）包围，使用decltype推导出的是表达式类型的引用（如果有 const volatile 限定符不能被忽略）
class Test1
{
    public:
        int num = 9;
        string text;
        static const int value = 110;
};
int main() 
{
    //定义类是加上限定 const
    const Test1 obj;//obj 是常量对象
    //带有括号的表达式
    //推导出 int 
    decltype(obj.num) a = 10;
    //加上小括号 推导出的是 const int& 
    decltype((obj.num)) b = a;
    int n = 0;
    int m = 0;
    //括号中n+m的结果是匿名变量，不是可修改左值  应此不会返回引用 地址
    decltype(n + m) c = 0;
    //n 为左值   int&
    decltype(n = n + m) d = n;
    return 0;
}